package com.pi.shisan.component.impl;

import com.pi.shisan.common.NumberUtil;
import com.pi.shisan.component.AnimationComponent;
import com.pi.shisan.component.util.AnimationThread;
import com.pi.shisan.component.util.ComponentThread;
import com.pi.shisan.util.spipoint.DataWriter;
import com.pi.shisan.util.spipoint.MergedSpi;
import com.pi.shisan.util.spipoint.MultipleFlushSpi;
import com.pi.shisan.util.spipoint.MultipleFlushSpiAsConsole;
import com.pi.shisan.util.spipoint.MultipleXyToSpiConverter;

/**
 * 进度条组件
 */
public class ProcessStateComponent extends AnimationComponent {

    private Integer lastValPoints;

    private int closeXy = -1;

    private double val;
    private double max = 1;

    public ProcessStateComponent(MultipleXyToSpiConverter spi, DataWriter dataWriter) {
        super(spi,dataWriter);
    }

    @Override
    protected AnimationThread prepareAnimation() {
        refreshAll();
        return new ProcessStateAnimationThread(this);
    }

    @Override
    public void refresh() {
        refreshAll();
    }

    private void refreshAll() {
        ComponentThread.execute(()->{
            for (int i = startX; i < startX + width; i++) {
                spi.put(i, startY + 1);
            }
            doRefresh(true);
            flushData();
        });
    }

    /**
     * 仅支持 0 - 100的操作
     * @param val
     */
    public void setVal(double val) {
        if (val > this.max) {
            val = this.max;
        }
        this.val = val;
        _setVal(val);
    }

    public void setMax(double max) {
        ComponentThread.execute(()->{
            double _max = max;
            if (_max <= 0) {
                _max = 1;
            }
            if (this.max != _max) {
                this.max = _max;
                refresh();
            }
        });
    }

    private void _setVal(double val) {
        ComponentThread.execute(()->{
            doRefresh(false);
        });
    }

    private void doRefresh(boolean force) {
        final double val = this.val;
        final double max = this.max;
        final int startX = this.startX;
        final int startY = this.startY;
        final int width = this.width - 1;
        int size = (int)(val / max * width);
        int currentPositoin = NumberUtil.toXy((short)(size + startX), (short)startY);
        if (!force && currentPositoin == lastValPoints) {
            return;
        }
        if (lastValPoints != null) {
            spi.delete(NumberUtil.toX(lastValPoints), NumberUtil.toY(lastValPoints));
        }
        spi.put(size + startX, startY);
        lastValPoints = currentPositoin;
        flushData();
    }

    private boolean drawLine() {
        int closeXy = this.closeXy;
        int x;
        if (closeXy > -1) {
            spi.put(x = NumberUtil.toX(closeXy), NumberUtil.toY(closeXy));
        } else {
            x = startX - 1;
        }
        final int startX = this.startX;
        final int width = this.width;
        final int startY = this.startY + 1;
        if (x >= startX + width - 1) {
            closeXy = -1;
            this.closeXy = closeXy;
            flushData();
            return true;
        }
        x ++;
        spi.delete(x, startY);
        closeXy = NumberUtil.toXy((short) x, (short) startY);
        this.closeXy = closeXy;
        flushData();
        return false;
    }

    static class ProcessStateAnimationThread extends AnimationThread {

        private ProcessStateComponent processStateComponent;

        public ProcessStateAnimationThread(ProcessStateComponent processStateComponent) {
            this.processStateComponent = processStateComponent;
            setName("process-state-animation");
        }

        @Override
        public void doRun() {
            while (!destroy) {
                boolean over = false;
                try {
                    over = ComponentThread.submit(processStateComponent::drawLine);
                } catch (Exception e) {
                }
                try {
                    Thread.sleep(over ? 3000 : 50);
                } catch (InterruptedException e) {
                }
            }
        }
    }

    public static void main(String[] args) throws Exception{

        MultipleFlushSpi multipleFlushSpi = new MultipleFlushSpiAsConsole(new MergedSpi(4,3));
        ProcessStateComponent processStateComponent = new ProcessStateComponent(multipleFlushSpi,multipleFlushSpi);
        processStateComponent.setY(22);
        processStateComponent.setH(10);
        processStateComponent.setW(26);
        processStateComponent.setX(3);
        for (int i = 0; i <= 100; i++) {
            System.out.println("val: "+i);
            processStateComponent.setVal(i);
            processStateComponent.start();
            Thread.sleep(1000);
        }
//        processStateComponent.destroy();
    }
}
